#pragma once
#include "socket.hpp"
#include "Log.hxx"
#include <string>
#include <vector>
#include <memory>
#include <array>
#include <sys/select.h>
#include <algorithm>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unordered_map>
#include "epoller.hpp"
#include  "Connection.hpp"

//指针设定规则，自定义类的裸指针必定是UnqiuePtr的拷贝


    using namespace EpollModule;
    using namespace Net_TcpSocket;
    //一次从epoller收入的事件个数
    const int Maxevents = 64;
    class EpollServer
    {
        Epoller _epoller;
        int _timeout;
        bool _IsRunning;
        std::vector<struct epoll_event> _events;
        std::unordered_map<int, std::shared_ptr<Connection>> _connections;
        uint64_t _mode = EPOLLET;
    public:
        //默认选择阻塞
        EpollServer(int timeout = -1)
        :_events(Maxevents)
        ,_timeout(timeout)
        {

        }
        ~EpollServer()
        {
            int tmp;
        }

        bool IsConnectExist(int sockfd)
        {
            return _connections.find(sockfd) != _connections.end();
        }
        
        //可以关闭默认的ET模式，那样就去按照Connection模式来
        void DisableETMode()
        {
            _mode = 0;
        }
        //打开默认ET模式
        void EnableETMode()
        {
            _mode = EPOLLET;
        }

        //添加链接默认选择ET模式
        void AddConnection(std::shared_ptr<Connection> connt) 
        {
            //空链接不添加
            if(connt== nullptr)
            {
                return ;
            }
            //已有链接不添加
            if(IsConnectExist(connt->GetFd()))
            {
                return ;
            }
            _epoller.AddFd(connt->GetFd(),connt->GetEvents() | _mode);
            _connections[connt->GetFd()] = connt;
        }
        void ModifyEvents(int sockfd,int NewEvents)
        {
            if(!IsConnectExist(sockfd))
            {
                return ;
            }
            _connections[sockfd]->SetEvents(NewEvents);
            _epoller.ModFd(sockfd,NewEvents | _mode);
            return ;
        }
        void DelConnection(int sockfd)
        {
            if(!IsConnectExist(sockfd))
                return ;
            _epoller.DelFd(sockfd);
            _connections[sockfd]->SetEvents(0);
            _connections.erase(sockfd);
        }
        void LoopOnce(int timeout)
        {
            DebugPrint();
            int ret = _epoller.Wait(_events.data(),_events.size(),timeout);
            for(int i = 0;i<ret;i++)
            {
                int sockfd = _events[i].data.fd;
                uint32_t events = _events[i].events;
                if((events & EPOLLHUP) || (events & EPOLLERR ))
                {
                    _connections[sockfd]->implementExcepter(_connections[sockfd]);
                }
                //下面再使用链接前，一定要判断是否存在，因为有可能上次就关闭移除了链接
                if((events & EPOLLIN) && IsConnectExist(sockfd))
                {
                    _connections[sockfd]->implementRecv(_connections[sockfd]);
                }
                if((events & EPOLLOUT) && IsConnectExist(sockfd))
                {
                    _connections[sockfd]->implementSend(_connections[sockfd]);
                }
                
            }
        }
        void DebugPrint()
        {
            //打印已经被epoll管理的文件描述符
            std::cout<<"已经管理的文件描述符\n";
            for(const auto& c:_connections)
            {
                std::cout<<c.first<<" ";
            }    
            std::cout<<"\n";
        }
        void WorkLoop()
        {
            while(1)
            {
                LoopOnce(_timeout);
            }
        }
    };